package com.example.codec;

import com.example.pojo.NettyMessage;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.handler.codec.MessageToMessageEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * <p>  </p>
 *
 * @author Chris
 * @since 2024/3/29 22:05
 */
public class NettyMessageEncoder extends MessageToByteEncoder<NettyMessage> {

    /**
     * 使用 slf4j 日志框架
     */
    private final static Logger log = LoggerFactory.getLogger(NettyMessageEncoder.class);

    MarshallingEncoder marshallingEncoder;

    public NettyMessageEncoder() throws IOException {
        this.marshallingEncoder = new MarshallingEncoder();
    }

    @Override
    protected void encode(ChannelHandlerContext ctx, NettyMessage msg, ByteBuf sendBuf) throws Exception {
        if (msg == null || msg.getHeader() == null) {
            throw new Exception("The encode message is null");
        }

        // 消息头
        // 校验码（4 字节） = 0xABEF + MajorVer(1) + MinorVer(1)
        sendBuf.writeInt(msg.getHeader().getCrcCode());
        // 长度（4 字节） = 包括消息头和消息体
        sendBuf.writeInt(msg.getHeader().getLength());
        // 会话 ID（8 字节）
        sendBuf.writeLong(msg.getHeader().getSessionID());
        // 类型（1 字节）
        sendBuf.writeByte(msg.getHeader().getType());
        // 消息优先级（1 字节）
        sendBuf.writeByte(msg.getHeader().getPriority());

        // 可选字段（变长，用于扩展消息头）：Total_len len1 seg1 len2 seg2 ...
        sendBuf.writeInt(msg.getHeader().getAttachment().size());
        for (Map.Entry<String, Object> entry : msg.getHeader().getAttachment().entrySet()) {
            // 编码 Key
            final byte[] keyArray = entry.getKey().getBytes();
            sendBuf.writeInt(keyArray.length);
            sendBuf.writeBytes(keyArray);
            // 编码 Value
            final Object value = entry.getValue();
            this.marshallingEncoder.encode(value, sendBuf);
        }

        if (msg.getBody() != null) {
            this.marshallingEncoder.encode(msg.getBody(), sendBuf);
        } else {
            sendBuf.writeInt(0);
        }

        sendBuf.setInt(4, sendBuf.readableBytes() - 8);
    }

}